package com.gooluke.mds.service.impl;

import com.gooluke.mds.common.annotation.Compare;
import com.gooluke.mds.common.constants.DataSourceName;
import com.gooluke.mds.dao.ConfigInfoMapper;
import com.gooluke.mds.datasource.DatasourceContextHolder;
import com.gooluke.mds.domain.dto.ConfigCompareDTO;
import com.gooluke.mds.domain.entity.TConfigInfo;
import com.gooluke.mds.domain.vo.ConfigDifferenceDesc;
import com.gooluke.mds.service.ConfigService;
import com.gooluke.mds.domain.vo.ConfigDifferentDetailVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author gooluke
 * description
 * datetime 2025-06-10 0:17
 */
@Service
@Slf4j
public class ConfigServiceImpl implements ConfigService {

    @Autowired
    private ConfigInfoMapper configInfoMapper;

    @Override
    public ConfigCompareDTO compareConfig() {
        DatasourceContextHolder.setDatasource(DataSourceName.SHANGHAI_01);
        List<TConfigInfo> sh01Configs = configInfoMapper.selectAllConfigs();
        DatasourceContextHolder.setDatasource(DataSourceName.SHANGHAI_02);
        List<TConfigInfo> sh02Configs = configInfoMapper.selectAllConfigs();
        // 调用比对方法
        List<ConfigDifferenceDesc> differentColumnInfos = new ArrayList<>();
        List<ConfigDifferentDetailVO> differences = compareConfigs(sh01Configs, sh02Configs, differentColumnInfos);

        // 输出差异结果
        differences.forEach(diff -> {
            System.out.println("差异配置: " + diff.getConfigName());
            System.out.println("SH01值: " + diff.getDb1Value() + ", 级别: " + diff.getDb1Level());
            System.out.println("SH02值: " + diff.getDb2Value() + ", 级别: " + diff.getDb2Level());
        });
        ConfigCompareDTO configCompareDTO = new ConfigCompareDTO();
        //configCompareDTO.setDifferentDetailVOList(differences);
        configCompareDTO.setDifferentColumnInfos(differentColumnInfos);
        return configCompareDTO;
    }

    public List<ConfigDifferentDetailVO> compareConfigs(List<TConfigInfo> sh01Configs, List<TConfigInfo> sh02Configs, List<ConfigDifferenceDesc> differentColumnInfos) {

        int i = 0, j = 0;
        List<ConfigDifferentDetailVO> differences = new ArrayList<>();

        while (i < sh01Configs.size() && j < sh02Configs.size()) {
            TConfigInfo config1 = sh01Configs.get(i);
            TConfigInfo config2 = sh02Configs.get(j);

            int cmp = config1.getConfigName().compareTo(config2.getConfigName());

            if (cmp == 0) {
                // 配置名相同，比较值和级别
                if (!configCompare(config1, config2)) {

                    ConfigDifferentDetailVO diff = new ConfigDifferentDetailVO();
                    diff.setConfigName(config1.getConfigName());
                    diff.setDb1Value(config1.getConfigValue());
                    diff.setDb1Level(config1.getConfigLevel());
                    diff.setDb2Value(config2.getConfigValue());
                    diff.setDb2Level(config2.getConfigLevel());
                    List<ConfigDifferentDetailVO.ColumnValueVO> columnValueVOS = buildColumnValueVOList("SH01", config1, "SH02", config2);
                    String columnDifference = getColumnDifference("SH01", config1, "SH02", config2);
                    differentColumnInfos.add(new ConfigDifferenceDesc(config1.getConfigName(),columnDifference));
                    diff.setDifferentColumns(columnValueVOS);
                    differences.add(diff);

                }
                i++;
                j++;
            } else if (cmp < 0) {
                // sh01中有而sh02中没有的配置
                ConfigDifferentDetailVO diff = new ConfigDifferentDetailVO();
                diff.setConfigName(config1.getConfigName());
                diff.setDb1Value(config1.getConfigValue());
                diff.setDb1Level(config1.getConfigLevel());
                diff.setDb2Value("MISSING");
                diff.setDb2Level(-1); // 用-1表示缺失
                List<ConfigDifferentDetailVO.ColumnValueVO> columnValueVOS = buildColumnValueVOList("SH01", config1, "SH02", null);
                diff.setDifferentColumns(columnValueVOS);
                differences.add(diff);
                String columnDifference = getColumnDifference("SH01", config1, "SH02", null);
                differentColumnInfos.add(new ConfigDifferenceDesc(config1.getConfigName(),columnDifference));
                i++;
            } else {
                // sh02中有而sh01中没有的配置
                ConfigDifferentDetailVO diff = new ConfigDifferentDetailVO();
                diff.setConfigName(config2.getConfigName());
                diff.setDb1Value("MISSING");
                diff.setDb1Level(-1); // 用-1表示缺失
                diff.setDb2Value(config2.getConfigValue());
                diff.setDb2Level(config2.getConfigLevel());
                List<ConfigDifferentDetailVO.ColumnValueVO> columnValueVOS = buildColumnValueVOList("SH01", null, "SH02", config2);
                diff.setDifferentColumns(columnValueVOS);
                differences.add(diff);
                String columnDifference = getColumnDifference("SH01", null, "SH02", config2);
                differentColumnInfos.add(new ConfigDifferenceDesc(config2.getConfigName(),columnDifference));
                j++;
            }
        }

        // 处理sh01中剩余的记录
        while (i < sh01Configs.size()) {
            TConfigInfo config1 = sh01Configs.get(i);
            ConfigDifferentDetailVO diff = new ConfigDifferentDetailVO();
            diff.setConfigName(config1.getConfigName());
            diff.setDb1Value(config1.getConfigValue());
            diff.setDb1Level(config1.getConfigLevel());
            diff.setDb2Value("MISSING");
            diff.setDb2Level(-1);
            List<ConfigDifferentDetailVO.ColumnValueVO> columnValueVOS = buildColumnValueVOList("SH01", config1, "SH02", null);
            diff.setDifferentColumns(columnValueVOS);
            differences.add(diff);
            String columnDifference = getColumnDifference("SH01", config1, "SH02", null);
            differentColumnInfos.add(new ConfigDifferenceDesc(config1.getConfigName(),columnDifference));
            i++;
        }

        // 处理sh02中剩余的记录
        while (j < sh02Configs.size()) {
            TConfigInfo config2 = sh02Configs.get(j);
            ConfigDifferentDetailVO diff = new ConfigDifferentDetailVO();
            diff.setConfigName(config2.getConfigName());
            diff.setDb1Value("MISSING");
            diff.setDb1Level(-1);
            diff.setDb2Value(config2.getConfigValue());
            diff.setDb2Level(config2.getConfigLevel());
            List<ConfigDifferentDetailVO.ColumnValueVO> columnValueVOS = buildColumnValueVOList("SH01", null, "SH02", config2);
            diff.setDifferentColumns(columnValueVOS);
            differences.add(diff);
            String columnDifference = getColumnDifference("SH01", null, "SH02", config2);
            differentColumnInfos.add(new ConfigDifferenceDesc(config2.getConfigName(),columnDifference));
            j++;
        }

        differentColumnInfos.forEach(System.out::println);

        return differences;
    }

    private boolean configCompare(TConfigInfo config1, TConfigInfo config2) {
        return (config1.getConfigValue().equals(config2.getConfigValue()) && config1.getConfigLevel().equals(config2.getConfigLevel()));
    }

    private List<ConfigDifferentDetailVO.ColumnValueVO> buildColumnValueVOList(String ds1, TConfigInfo config1, String ds2, TConfigInfo config2) {
        List<ConfigDifferentDetailVO.ColumnValueVO> list = new ArrayList<>();
        Field[] fields = TConfigInfo.class.getDeclaredFields();
        for (Field field : fields) {
            Compare annotation = field.getAnnotation(Compare.class);
            if (annotation == null) {
                continue;
            }
            try {
                ConfigDifferentDetailVO.ColumnValueVO columnValueVO = new ConfigDifferentDetailVO.ColumnValueVO();
                field.setAccessible(true);
                columnValueVO.setColumnName(field.getName());
                String value1 = (config1 == null ? null : (field.get(config1) == null ? null : field.get(config1).toString()));
                String value2 = (config2 == null ? null : (field.get(config2) == null ? null : field.get(config2).toString()));
                if (!StringUtils.equals(value1, value2)) {
                    columnValueVO.setColumnValues(Arrays.asList(ds1 + ":" + value1, ds2 + ":" + value2));
                    list.add(columnValueVO);
                }
            } catch (Exception e) {
                log.error("buildColumnValueVOList exception: ", e);
                throw new RuntimeException("Failed to build column value VO list");
            }
        }
        return list;
    }

    private String getColumnDifference(String ds1, TConfigInfo config1, String ds2, TConfigInfo config2) {
        String descriptionTemplate = "字段%s差异：%s值为：[%s],%s值为：[%s];";
        StringBuilder sb = new StringBuilder();
        Field[] fields = TConfigInfo.class.getDeclaredFields();
        for (Field field : fields) {
            Compare annotation = field.getAnnotation(Compare.class);
            if (annotation == null) {
                continue;
            }
            try {
                field.setAccessible(true);
                String value1 = (config1 == null ? null : (field.get(config1) == null ? null : field.get(config1).toString()));
                String value2 = (config2 == null ? null : (field.get(config2) == null ? null : field.get(config2).toString()));
                if (!StringUtils.equals(value1, value2)) {
                    String format = String.format(descriptionTemplate, field.getName(), ds1, value1, ds2, value2);
                    sb.append(format);
                }
            } catch (Exception e) {
                log.error("buildColumnValueVOList exception: ", e);
                throw new RuntimeException("Failed to build column value VO list");
            }
        }
        return sb.toString();
    }
}
